#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <unistd.h>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <map>

#define MAXROUTERS 10
#define MAXFILENAME 128
#define MAXLINE 1024
#define INF 1001

std::map<int, int> alloc_id;
int alloc_id_inv[MAXROUTERS];

enum MessageType
{
    R2R = 1,
    R2A,
    A2R,
};

enum CommandType
{
    DV = 1,
    UPDATE,
    SHOW,
    RESET,
};

enum ReplyType
{
    SEND = 1,
    REPLY,
    // START,
};

struct Router
{
    char router_ip[20];
    u_int16_t router_port;
    int router_id;
    sockaddr_in router_addr;
    socklen_t addr_len;
    void set_router(char *buffer, int aid)
    {
        // char buffer[MAXLINE];
        // scanf("%s", buffer);
        char *pos = strchr(buffer, ',');
        if (pos == NULL)
        {
            perror("router file format error.");
            exit(EXIT_FAILURE);
        }
        (*pos) = ' ';
        sscanf(buffer, "%s %hu,%d", router_ip, &router_port, &router_id);
        // printf("set_router: %s,%hu,%d\n", router_ip, router_port, router_id);
        alloc_id[router_id] = aid;
        alloc_id_inv[aid] = router_id;
        router_id = aid;
        // memcpy(router_ip, buffer, pos - buffer);
        // router_ip[pos - buffer] = '\0';

        memset(&router_addr, 0, sizeof(router_addr));
        router_addr.sin_family = AF_INET;
        router_addr.sin_port = htons(router_port);
        addr_len = sizeof(struct sockaddr_in);
        if (inet_pton(AF_INET, router_ip, &router_addr.sin_addr) <= 0)
        {
            perror("address failed");
            exit(EXIT_FAILURE);
        }
    }
};

struct RTE
{
    int dest, next, cost;
    void tostring(char *buf)
    {
        sprintf(buf, "dest: %d, next: %d, cost: %d\n", alloc_id_inv[dest], alloc_id_inv[next], cost);
    }
};

struct Message
{
    MessageType message_type;
    int len;
    Message()
    {
        len = sizeof(Message);
    }
};

struct MessageR2R : Message
{
    ReplyType reply_type;
    int source;
    int seq;
    int dv[MAXROUTERS];
    MessageR2R()
    {
        len = sizeof(MessageR2R);
    }
    MessageR2R(ReplyType _reply_type, int _source, int _seq) : reply_type(_reply_type), source(_source), seq(_seq)
    {
        len = sizeof(MessageR2R);
        message_type = R2R;
    }
};

struct MessageA2R : Message
{
    CommandType command_type;
    MessageA2R()
    {
        len = sizeof(MessageA2R);
        message_type = A2R;
    }
};

struct MessageA2RUpdate : MessageA2R
{
    int from, to, value;
    MessageA2RUpdate(int _0, int _1, int _2) : from(_0), to(_1), value(_2)
    {
        len = sizeof(MessageA2RUpdate);
        command_type = UPDATE;
    }
};

struct MessageA2RDv : MessageA2R
{
    MessageA2RDv()
    {
        len = sizeof(MessageA2RDv);
        command_type = DV;
    }
};

struct MessageA2RShow : MessageA2R
{
    MessageA2RShow()
    {
        len = sizeof(MessageA2RShow);
        command_type = SHOW;
    }
};

struct MessageA2RReset : MessageA2R
{
    MessageA2RReset()
    {
        len = sizeof(MessageA2RReset);
        command_type = RESET;
    }
};

struct MessageR2A : Message
{
    int pl_len;
    MessageR2A(int _pl_len)
    {
        message_type = R2A;
        pl_len = _pl_len;
        len = sizeof(MessageR2A) + pl_len;
    }
};

ssize_t rio_readn(int fd, void *usrbuf, size_t n)
{
    size_t nleft = n;
    ssize_t nread;
    char *bufp = (char *)usrbuf;

    while (nleft > 0)
    {
        if ((nread = read(fd, bufp, nleft)) < 0)
        {
            if (errno == EINTR) /* Interrupted by sig handler return */
                nread = 0;      /* and call read() again */
            else
                return -1; /* errno set by read() */
        }
        else if (nread == 0)
            break; /* EOF */
        nleft -= nread;
        bufp += nread;
    }
    return (n - nleft); /* return >= 0 */
}
/* $end rio_readn */

/*
 * rio_writen - Robustly write n bytes (unbuffered)
 */
/* $begin rio_writen */
ssize_t rio_writen(int fd, void *usrbuf, size_t n)
{
    size_t nleft = n;
    ssize_t nwritten;
    char *bufp = (char *)usrbuf;

    while (nleft > 0)
    {
        if ((nwritten = write(fd, bufp, nleft)) <= 0)
        {
            if (errno == EINTR) /* Interrupted by sig handler return */
                nwritten = 0;   /* and call write() again */
            else
                return -1; /* errno set by write() */
        }
        nleft -= nwritten;
        bufp += nwritten;
    }
    return n;
}

ssize_t Rio_readn(int fd, void *ptr, size_t nbytes)
{
    ssize_t n;

    if ((n = rio_readn(fd, ptr, nbytes)) < 0)
    {
        printf("Rio_readn error: %s\n", strerror(errno));
        perror("Rio_readn error");
        exit(EXIT_FAILURE);
    }
    return n;
}

void Rio_writen(int fd, void *usrbuf, size_t n)
{
    if (rio_writen(fd, usrbuf, n) != (ssize_t)n)
    {
        perror("Rio_writen error");
        exit(EXIT_FAILURE);
    }
}